//
//  SDNavigationController.m
//  SKinDiary
//
//  Created by pcyang on 16/6/26.
//  Copyright © 2016年 tencent. All rights reserved.
//

#import "SDNavigationController.h"

#define MinVersion 7.0

typedef void (^QLTransitionBlock)(void);

@interface SDNavigationController () <UIGestureRecognizerDelegate> {
    CGPoint _startTouch;
    UIView *_blackMask;
    
    NSMutableArray * _otherGestures;
    
    //safe transition
    BOOL _transitionInProgress;
    NSMutableArray *_panBlocks;
    CGFloat _systemVersion;
    //end safe transition
    
}
@property (nonatomic,strong) UIView *backgroundView;
@property (nonatomic,strong) NSMutableArray *screenShotsList;
@property (nonatomic,strong) UIImageView *lastScreenShotView;

@property (nonatomic, assign) BOOL isInSafeMode;

@property (nonatomic, weak) UIViewController * lastPushViewCtl;

@end

@implementation SDNavigationController


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        _systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
        
        _transitionInProgress = NO;
        
        self.screenShotsList = [[NSMutableArray alloc]initWithCapacity:2];
        
        _otherGestures = [[NSMutableArray alloc] init];
        
        _panBlocks = [NSMutableArray arrayWithCapacity:2];
        
        // 默认全局支持恒划返回
        self.dragBackType = SDPageCtlDragbackTypeNone;
        
        self.delegate = self;
    }
    return self;
    
}

-(void)viewDidLoad{
    [super viewDidLoad];
    
    self.navigationBar.hidden = YES;
    
    self.interactivePopGestureRecognizer.enabled = NO;
    
    if ( self.dragBackType != SDPageCtlDragbackTypeNone )
    {
        //view左边缘的黑条边
        UIImageView *shadowImageView = [[UIImageView alloc]initWithImage:LOAD_IMAGE_USE_CACHE_INBUNDLE(DefaultBundle, @"leftside_shadow_bg.png")];
        shadowImageView.frame = CGRectMake(-10, 0, 10, self.view.frame.size.height);
        [self.view addSubview:shadowImageView];
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_5_1

- (BOOL) shouldAutorotate NS_AVAILABLE_IOS(6_0)
{
    return [self.topViewController shouldAutorotate];
}
- (UIInterfaceOrientationMask) supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0)
{
    return [self.topViewController supportedInterfaceOrientations];
}
#endif

#pragma mark BEGIN Safe Transition

- (void)beginSafeMode {
    _isInSafeMode = YES;
}

- (void)endSafeMode {
    _isInSafeMode = NO;
}

#pragma mark - Transition Manager

- (void)addTransitionBlock:(void (^)(void))block
{
    if (![self isTransitionInProgress]) {
        self.transitionInProgress = YES;
        block();
    }
    else {
        [_panBlocks addObject:[block copy]];
    }
}

- (BOOL)isTransitionInProgress
{
    return _transitionInProgress;
}

- (void)setTransitionInProgress:(BOOL)transitionInProgress
{
    _transitionInProgress = transitionInProgress;
    if (!transitionInProgress && _panBlocks.count > 0) {
        _transitionInProgress = YES;
        [self runNextTransition];
    }
}

- (void)runNextTransition
{
    QLTransitionBlock block = _panBlocks.firstObject;
    [_panBlocks removeObject:block];
    block();
}


#pragma mark - panGesture

//覆盖系统方法
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if ( self.lastPushViewCtl && self.lastPushViewCtl == viewController )
    {
        [super pushViewController:viewController animated:animated];
        return;
    }
    
    if (_systemVersion >= MinVersion)
    {
        [self mypushViewController:viewController animated:animated];
    }
    else
    {
        __weak SDNavigationController *weakSelf = self;
        [self addTransitionBlock:^{
            [weakSelf mypushViewController:viewController animated:animated];
        }];
    }
    
    self.lastPushViewCtl = viewController;
}

- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
    UIViewController *poppedViewController = nil;
    if (_systemVersion >= MinVersion)
    {
        poppedViewController = [self mypopViewControllerAnimated:animated];
    }
    else {
        __weak SDNavigationController *weakSelf = self;
        [self addTransitionBlock:^{
            UIViewController *viewController = [weakSelf mypopViewControllerAnimated:animated];
            if (viewController == nil) {
                weakSelf.transitionInProgress = NO;
            }
        }];
    }
    
    self.lastPushViewCtl = self.viewControllers.lastObject;
    
    return poppedViewController;
}

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    NSArray *poppedViewControllers = nil;
    if (_systemVersion >= MinVersion) {
        poppedViewControllers = [self mypopToViewController:viewController animated:animated];
    }
    else {
        __weak SDNavigationController *weakSelf = self;
        [self addTransitionBlock:^{
            if ([weakSelf.viewControllers containsObject:viewController]) {
                NSArray *viewControllers = [weakSelf mypopToViewController:viewController animated:animated];
                if (viewControllers.count == 0) {
                    weakSelf.transitionInProgress = NO;
                }
            }
            else {
                weakSelf.transitionInProgress = NO;
            }
        }];
    }
    return poppedViewControllers;
}

- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
{
    NSArray *poppedViewControllers = nil;
    if (_systemVersion >= MinVersion) {
        poppedViewControllers = [self mypopToRootViewControllerAnimated:animated];
    }
    else {
        __weak SDNavigationController *weakSelf = self;
        [self addTransitionBlock:^{
            NSArray *viewControllers = [weakSelf mypopToRootViewControllerAnimated:animated];
            if (viewControllers.count == 0) {
                weakSelf.transitionInProgress = NO;
            }
        }];
    }
    return poppedViewControllers;
}

- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
{
    if (_systemVersion >= MinVersion) {
        [super setViewControllers:viewControllers animated:animated];
    }
    else {
        __weak SDNavigationController *weakSelf = self;
        [self addTransitionBlock:^{
            NSArray *originalViewControllers = weakSelf.viewControllers;
            NSLog(@"%s", __FUNCTION__);
            [super setViewControllers:viewControllers animated:animated];
            if (!animated || originalViewControllers.lastObject == viewControllers.lastObject) {
                weakSelf.transitionInProgress = NO;
            }
        }];
    }
}

#pragma mark - UINavigationControllerDelegate

/**
 *  通过Delegate的响应，解决连续多次首次响应弹出 viewController 导致的 crash 问题
 *
 *  @param navigationController 系统当前的 UINavigationController
 *  @param viewController       系统当前的 UIViewController
 *  @param animated             系统当前的  动画是否存在
 */

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    [self removePaningGesture];
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    
    [_otherGestures removeAllObjects];
    
    [self confirmDragbackGesture:viewController];
}

// override the push method
- (void)mypushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // 这里设置 Translucent 是为了解决在真机上截图黑底的问题
    // Translucent is NO before capture
    UIViewController * viewCtl = [self topViewController];
    
//    if ([viewCtl isKindOfClass:[SDTabBarController class]])
//    {
//        [(SDTabBarController *)viewCtl prepareForScreenshort];
//        [self pushScreenShot];
//        [(SDTabBarController *)viewCtl endScreenshot];
//    }
//    else if ( [viewCtl isKindOfClass:[SDBaseViewController class]] && !_isInSafeMode && [(SDBaseViewController *)viewCtl shouldCacheScreenShot] )
//    {
//        [(SDBaseViewController *)viewCtl prepareForScreenshort];
//        [self pushScreenShot];
//        [(SDBaseViewController *)viewCtl endScreenshot];
//    }
    
    [super pushViewController:viewController animated:animated];
}
// override the pop method
- (UIViewController *)mypopViewControllerAnimated:(BOOL)animated
{
    [self removeCurScreenShot];
    
    NSArray * vCtls = self.viewControllers;
    if ( vCtls.count > 1 ) {
        id <SDNavigationDragBackSupport> toCtl = [vCtls objectAtIndex:vCtls.count - 2];
        if ([toCtl respondsToSelector:@selector(dragBackType)] ) {
            
            self.dragBackType = [toCtl dragBackType];
            
            if ( SDPageCtlDragbackTypeNone == self.dragBackType ) {
                [self removePaningGesture];
            }
        }
    }
    
    return [super popViewControllerAnimated:animated];
}
- (NSArray*)mypopToViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    NSArray * vCtls = self.viewControllers;
    int index = 0;
    for (int i = (int)[vCtls count] - 1 ; i >= 0 ; --i) {
        id toCtl = [vCtls objectAtIndex:i];
        index++;
        if ((toCtl == viewController) && [toCtl isKindOfClass:[viewController class]]) {
            if ([toCtl respondsToSelector:@selector(dragBackType)] ) {
                
                self.dragBackType = [toCtl dragBackType];
                
                if ( SDPageCtlDragbackTypeNone == self.dragBackType ) {
                    [self removePaningGesture];
                }
            }
            break;
        }
    }
    
    NSArray* array = [super popToViewController:viewController animated:animated];
    
    if ([self.screenShotsList count] > index - 1) {
        --index;
        while (index) {
            [self.screenShotsList removeLastObject];
            -- index;
        }
    }
    return array;
}

- (NSArray *)mypopToRootViewControllerAnimated:(BOOL)animated
{
    NSArray* ret = [super popToRootViewControllerAnimated:animated];
    return ret;
}


- (void)removePaningGesture
{
    if (_recognizer)
    {
        [self.view removeGestureRecognizer:_recognizer];
        _recognizer = nil;
    }
}

- (void)confirmDragbackGesture:(UIViewController *)viewCtl {
    if ([viewCtl respondsToSelector:@selector(dragBackType)])
    {
        id<SDNavigationDragBackSupport> controller = (id<SDNavigationDragBackSupport>)viewCtl;
        
        self.dragBackType = [controller dragBackType];
        
        if ( SDPageCtlDragbackTypeNone == self.dragBackType ) {
            [self removePaningGesture];
        } else {
            [self addPaningGesture:(SDBaseViewController *)controller];
        }
    } else {
        [self addPaningGesture:nil];
    }
}

- (void)addPaningGesture:(SDBaseViewController *)viewCtl
{
    if (_recognizer) {
        return;
    }
    
    if ( SDPageCtlDragbackTypeDefault == self.dragBackType ) {
        _recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(paningGestureReceive:)];
        
        _recognizer.delegate = self;
        ((UIPanGestureRecognizer *)_recognizer).maximumNumberOfTouches = 1;
        
    } else if ( SDPageCtlDragbackTypeLeftEdge == self.dragBackType && _systemVersion >7.0) {
        _recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(paningGestureReceive:)];
        ((UIScreenEdgePanGestureRecognizer *)_recognizer).edges = UIRectEdgeLeft;
    }
    
    if ( _recognizer ) {
        [self.view addGestureRecognizer:_recognizer];
    }
    return;
}

- (UIImage *)pushScreenShot {
    UIImage *snapshot = [SDNavigationController screenshot];
    if (snapshot) {
        [self.screenShotsList addObject:snapshot];
    }
    
    return snapshot;
}

- (void)removeCurScreenShot {
    if ([self.screenShotsList count] > 0 && !_isInSafeMode ) {
        [self.screenShotsList removeLastObject];
    }
}

+ (UIImage*)screenshot
{
    CGSize imageSize = CGSizeZero;
    
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if (UIInterfaceOrientationIsPortrait(orientation)) {
        imageSize = [UIScreen mainScreen].bounds.size;
    } else {
        imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
    }
    
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
        CGContextSaveGState(context);
        CGContextTranslateCTM(context, window.center.x, window.center.y);
        CGContextConcatCTM(context, window.transform);
        CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
        if (orientation == UIInterfaceOrientationLandscapeLeft) {
            CGContextRotateCTM(context, M_PI_2);
            CGContextTranslateCTM(context, 0, -imageSize.width);
        } else if (orientation == UIInterfaceOrientationLandscapeRight) {
            CGContextRotateCTM(context, -M_PI_2);
            CGContextTranslateCTM(context, -imageSize.height, 0);
        } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
            CGContextRotateCTM(context, M_PI);
            CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
        }
        if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
            [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
        } else {
            [window.layer renderInContext:context];
        }
        
        CGContextRestoreGState(context);
    }
    
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return image;
}

// set lastScreenShotView 's position and alpha when paning
- (void) moveViewWithX:(float)x {
    
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    x = x>screenWidth?screenWidth:x;
    x = x<0?0:x;
    
    CGRect frame = self.view.frame;
    frame.origin.x = x;
    self.view.frame = frame;
    
    _lastScreenShotView.left = self.view.left * 0.3 - _lastScreenShotView.width * 0.3;
    
    float alpha = 0.4 - (x/800);
    _blackMask.alpha = alpha;
}

- (void)realPopViewControllerAnimated:(BOOL)animated {
    NSArray * vCtls = self.viewControllers;
    id <SDNavigationDragBackSupport> toCtlReport = [self.viewControllers objectAtIndex:vCtls.count - 1];
    
    if ( [toCtlReport respondsToSelector:@selector(popUp:)] ) {
        [(SDBaseViewController *)toCtlReport popUp:animated];
    } else {
        [self popViewControllerAnimated:animated];
    }
    
    if ( !animated ) {
        CGRect frame = self.view.frame;
        frame.origin.x = 0;
        self.view.frame = frame;
    }
}

#pragma mark    UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)panGestureRecognizer
{
    [_otherGestures removeAllObjects];
    
    BOOL ret = NO;
    
    CGPoint translation = [panGestureRecognizer translationInView:self.view];
    CGPoint velocity = [panGestureRecognizer velocityInView:self.view];
    
    // 某些页面特殊处理
    
    UIViewController * viewCtl = self.visibleViewController;
    CGPoint location = [panGestureRecognizer locationInView:self.view];
    
    if ( [viewCtl isKindOfClass:[SDBaseViewController class]] ) {
        if ( [(SDBaseViewController*)viewCtl responseDragbackAtScreenPoint:location] ) {
            ret = (translation.x >= 0 &&
                   fabs(translation.x) >= fabs(translation.y) &&
                   fabs(velocity.x) > fabs(velocity.y)
                   );
        } else {
            return NO;
        }
    } else {
        return NO;
    }
    
    return ret;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    //    NSLog(@"ges : %@, other : %@",gestureRecognizer,otherGestureRecognizer);
    
    [_otherGestures addObject:otherGestureRecognizer];
    
    return YES;
}

- (void)paningGestureReceive:(UIPanGestureRecognizer *)recoginzer {
    // If the viewControllers has only one vc or disable the interaction, then return.
    if (self.viewControllers.count <= 1 || self.dragBackType == SDPageCtlDragbackTypeNone ) return;
    // we get the touch position by the window's coordinate
    CGPoint touchPoint = [recoginzer locationInView:[[UIApplication sharedApplication] keyWindow]];
    // begin paning, show the backgroundView(last screenshot),if not exist, create it.
    if (recoginzer.state == UIGestureRecognizerStateBegan) {
        
        // Remove
        for ( UIGestureRecognizer * gesture in _otherGestures ) {
            gesture.enabled = NO;
            gesture.enabled = YES;
        }
        
        [_otherGestures removeAllObjects];
        
        _isMoving = YES;
        _startTouch = touchPoint;
        
        if (!self.backgroundView)
        {
            CGRect frame = self.view.frame;
            
            self.backgroundView = [[UIView alloc] initWithFrame:
                                   CGRectMake(0, 0, frame.size.width , frame.size.height)];
            _blackMask = [[UIView alloc]initWithFrame:
                          CGRectMake(0, 0, frame.size.width , frame.size.height)];
            _blackMask.backgroundColor = [UIColor blackColor];
            [self.backgroundView addSubview:_blackMask];
        }
        self.backgroundView.hidden = NO;
        
        if (_lastScreenShotView) {
            [_lastScreenShotView removeFromSuperview];
            _lastScreenShotView = nil;
        }
        
        UIImage *lastScreenShot = [self.screenShotsList lastObject];
        _lastScreenShotView = [[UIImageView alloc]initWithImage:lastScreenShot];
        _lastScreenShotView.frame = self.view.bounds;
        _lastScreenShotView.right = _lastScreenShotView.width / 2.0;
        
        
        [self.backgroundView insertSubview:_lastScreenShotView belowSubview:_blackMask];
        [self.view.superview insertSubview:self.backgroundView belowSubview:self.view];
        //End paning, always check that if it should move right or move left automatically
    }else if (recoginzer.state == UIGestureRecognizerStateEnded) {
        
        [_otherGestures removeAllObjects];
        
        CGPoint velocity = [recoginzer velocityInView:self.view];
        
        // 横向速度大于 1000 直接返回
        if ( (velocity.x > 1000) || (touchPoint.x - _startTouch.x > 100) )
        {
            [UIView animateWithDuration:0.3 animations:^{
                [self moveViewWithX:[UIScreen mainScreen].bounds.size.width];
            } completion:^(BOOL finished) {
                [self realPopViewControllerAnimated:NO];
                _isMoving = NO;
                self.backgroundView.hidden = YES;
            }];
        }
        else
        {
            [UIView animateWithDuration:0.3 animations:^{
                [self moveViewWithX:0];
            } completion:^(BOOL finished) {
                _isMoving = NO;
                self.backgroundView.hidden = YES;
            }];
        }
        return;
        // cancal panning, alway move to left side automatically
    }else if (recoginzer.state == UIGestureRecognizerStateCancelled) {
        [_otherGestures removeAllObjects];
        
        [UIView animateWithDuration:0.3 animations:^{
            [self moveViewWithX:0];
        } completion:^(BOOL finished) {
            _isMoving = NO;
            self.backgroundView.hidden = YES;
        }];
        return;
    }
    // it keeps move with touch
    if (_isMoving) {
        [self moveViewWithX:touchPoint.x - _startTouch.x];
    }
}

@end
